#ifndef StarsInterpreter_H
#define StarsInterpreter_H

#include "BufferedJsonIoService.h"

#include "model-server/MsgHandler.h"

#include "simodo/shell/runner/Runner_interface.h"
#include "simodo/shell/runner/Runner_plugin.h"
#include "simodo/shell/access/RunnerManagement_interface.h"

#include <QObject>

#include <thread>
#include <mutex>
#include <condition_variable>
#include <memory>
#include <atomic>
#include <optional>

namespace shell  = simodo::shell;
namespace model_server = simodo::edit::plugin::model_server;

class StarsInterpreter : public QObject,
                     public shell::Runner_interface
{
    Q_OBJECT

public:
    struct RecordEvent;

public:
    StarsInterpreter(shell::Runner_plugin * plugin, shell::Access_interface & shell);
    ~StarsInterpreter();

public:
    // shell::Runner_interface
    virtual shell::Runner_plugin * plugin() override { return _plugin; }
    virtual QString name() const override;
    virtual QString description() const override;
    virtual bool isRunnable(const QString & path) override;
    virtual bool startModeling(const QString & path) override;
    virtual bool pauseModeling() override;
    virtual bool stopModeling() override;
    virtual bool send(const QString & data) override;
    virtual QString error_text() override { return _error_text; }
    virtual QWidget * getToolbarWidget() override { return nullptr; }
    virtual bool isAutoRunActive() const override { return false; }
    virtual void setAutoRunActive(bool ) override {}

protected:
    bool event(QEvent * event) override;

private slots:
    void notification_received_slot(const QString text);
    void ran_slot();
    void paused_slot();
    void stoped_slot();

signals:
    void ran_signal(const QString & path);
    void stoped_signal(const QString & path);
    void paused_signal(const QString & path);
    void notification_received_signal(const QString text);

    void shell_send_global_signal(const QString & text, int severity);

private slots:
    void shell_send_global_slot(const QString & text, int severity);
    void _processServerMessage(QJsonDocument message);
    void _processServerMessages(QVector<QJsonDocument> messages);

private:
    shell::Runner_plugin *      _plugin;
    shell::Access_interface &   _shell;
    shell::RunnerState          _state = shell::RunnerState::Stoped;

    QString                     _error_text;

    QThread _buffer_thread;
    BufferedJsonIoService _server;

    std::vector<std::shared_ptr<model_server::MsgHandler>>
        _msg_handlers;

    bool _writeMessage(QJsonObject message);
};

struct StarsInterpreter::RecordEvent : public QEvent
{
    static const QEvent::Type TYPE;
    QString record;
    std::optional<shell::MessageSeverity> severity;
    RecordEvent(QString record, std::optional<shell::MessageSeverity> severity = {});
};

#endif // StarsInterpreter_H
